<?php

namespace app\admin\service\common\token;

use think\facade\Cache;
use think\facade\Log;

class CacheTokenRepository implements TokenRepositoryInterface
{
    protected string $keyPrefix = 'admin_token:';
    protected string $userKeyPrefix = 'admin_user_tokens:';

    public function save(array $tokenInfo, string $type): void
    {
        try {
            $tokenKey = $this->keyPrefix . $type . ':' . $tokenInfo['accessToken'];
            $userKey = $this->userKeyPrefix . $tokenInfo['username'];

            $data = [
                'user_id' => $tokenInfo['id'],
                'username' => $tokenInfo['username'] ?? '',
                'access_token' => $tokenInfo['accessToken'] ?? '',
                'refresh_token' => $tokenInfo['refreshToken'] ?? '',
                'expired' => $tokenInfo['expireTime'] ?? 0,
                'expired_date' => date('Y-m-d H:i:s', $tokenInfo['expireTime']),
                'expire_time' => $tokenInfo['expireTime'] ?? 0,
                'refresh_expire_time' => $tokenInfo['refreshExpireTime'] ?? 0,
                'type' => $type,
                'online' => time(),
                'status' => 1,
                'create_time' => time(),
                'update_time' => time(),
            ];

            // 保存token信息
            $ttl = $tokenInfo['expireTime'] - time();
            if ($ttl > 0) {
                Cache::set($tokenKey, $data, $ttl);
                // 维护用户的token列表
                $userTokens = Cache::get($userKey, []);
                $userTokens[] = $tokenInfo['accessToken'];
                Cache::set($userKey, array_unique($userTokens), $ttl);
            }

            trace("Token saved to Redis: {$type} for user {$data['username']}");
        } catch (\Exception $e) {
            Log::error("Failed to save token to Redis: " . $e->getMessage());
            throw $e;
        }
    }

    public function findByUser(string $username): array
    {
        try {
            $userKey = $this->userKeyPrefix . $username;
            $tokens = Cache::get($userKey, []);

            $result = [];
            foreach ($tokens as $token) {
                $tokenData = $this->find($token, 'access') ?: $this->find($token, 'refresh');
                if ($tokenData) {
                    $result[] = $tokenData;
                }
            }

            return $result;
        } catch (\Exception $e) {
            Log::error("Failed to find tokens by user in Redis: " . $e->getMessage());
            return [];
        }
    }

    public function find(string $token, string $type): ?array
    {
        try {
            $tokenKey = $this->keyPrefix . $type . ':' . $token;
            $result = Cache::get($tokenKey);

            return $result ?: null;
        } catch (\Exception $e) {
            Log::error("Failed to find token in Redis: " . $e->getMessage());
            return null;
        }
    }

    public function deleteByUser(string $username): void
    {
        try {
            $userKey = $this->userKeyPrefix . $username;
            $tokens = Cache::get($userKey, []);

            foreach ($tokens as $token) {
                $this->delete($token, 'access');
                $this->delete($token, 'refresh');
            }

            Cache::delete($userKey);
            trace("All tokens deleted for user: {$username}");
        } catch (\Exception $e) {
            Log::error("Failed to delete tokens by user in Redis: " . $e->getMessage());
            throw $e;
        }
    }

    public function delete(string $token, string $type): void
    {
        try {
            $tokenKey = $this->keyPrefix . $type . ':' . $token;

            // 获取token信息以便从用户token列表中移除
            $tokenData = Cache::get($tokenKey);
            if ($tokenData && isset($tokenData['username'])) {
                $userKey = $this->userKeyPrefix . $tokenData['username'];
                $userTokens = Cache::get($userKey, []);
                $userTokens = array_diff($userTokens, [$token]);
                Cache::set($userKey, $userTokens);
            }

            Cache::delete($tokenKey);
            trace("Token deleted from Redis: {$type}");
        } catch (\Exception $e) {
            Log::error("Failed to delete token from Redis: " . $e->getMessage());
            throw $e;
        }
    }

    public function updateOnline(string $token): void
    {
        try {
            $tokenKey = $this->keyPrefix . 'access' . ":" . $token;
            $tokenData = Cache::get($tokenKey);

            if ($tokenData) {
                $tokenData["online"] = time();
                $ttl = $tokenData["expired"] - time();
                if ($ttl > 0) {
                    Cache::set($tokenKey, $tokenData, $ttl);
                    trace("Token online time has updated  for token: {$token}");
                } else {
                    trace("Attempted to update online status for an expired token: {$token}");
                }
            } else {
                trace("Token not found in cache for online status update: {$token}");
            }
        } catch (\Exception $e) {
            Log::error("Failed to update token online status in Redis: " . $e->getMessage());
            throw $e;
        }
    }

    public function deleteExpired(): void
    {
        try {
            // Redis的TTL机制会自动清理过期的key，这里只需要记录日志
            trace("Redis TTL mechanism handles expired token cleanup automatically");
        } catch (\Exception $e) {
            Log::error("Failed to handle expired tokens in Redis: " . $e->getMessage());
            throw $e;
        }
    }
}